package com.sleepcamel.resteasyConfigurator.view.detail;

import java.lang.reflect.ParameterizedType;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.fieldassist.AutoCompleteField;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

import com.sleepcamel.rest.domain.method.parameter.MethodParameter;
import com.sleepcamel.resteasyConfigurator.util.ClassProvider;
import com.sleepcamel.resteasyConfigurator.view.updateValueStrategies.ClassToStringUpdateValueStrategy;
import com.sleepcamel.resteasyConfigurator.view.updateValueStrategies.StringToClassUpdateValueStrategy;

@SuppressWarnings("unchecked")
public class MethodParameterView<T extends MethodParameter> extends DetailView<T> {
	private Text txtReturnType;
	private Text txtMethodName;
	private Binding nameBinding;
	private Binding returnTypeBinding;
	private Action addCallback;

	public MethodParameterView(Composite parent, int style) {
		super(parent, style);
		setLayout(new RowLayout(SWT.HORIZONTAL));
		createControl();
		clear();
	}
	
	protected void createControl(){
		txtReturnType = new Text(this, SWT.BORDER);
		txtReturnType.setMessage("return type");
		new AutoCompleteField(txtReturnType, new TextContentAdapter(), ClassProvider.getInstance().getClassesNames());
		
		txtMethodName = new Text(this, SWT.BORDER);
		txtMethodName.setMessage("name");
		
		Button btnAdd = new Button(this, SWT.PUSH);
		btnAdd.setText("Add");
		btnAdd.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent event) {
				if (getParameter() != null) {
					if ( addCallback != null ){
						addCallback.run();
					}
					clear();
				}
			}
		});

		Button btnRemove = new Button(this, SWT.PUSH);
		btnRemove.setText("Remove");
		btnRemove.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				clear();
			}
		});
	}

	public void setModelData(T data) {
		clearBindings();
		super.setModelData(data);
	}

	protected void clearBindings() {
		clearBinding(returnTypeBinding);
		clearBinding(nameBinding);
	}

	protected void clearBinding(Binding binding) {
		if ( binding != null ){
			binding.dispose();
			m_bindingContext.removeBinding(binding);
		}
	}
	
	protected DataBindingContext initDataBindings() {
		super.initDataBindings();
		
		IObservableValue returnTypeObserveWidget = SWTObservables.observeText(txtReturnType, SWT.Modify);
		IObservableValue returnTypeObserveValue = BeansObservables.observeValue(modelData, "type");
		returnTypeBinding = m_bindingContext.bindValue(returnTypeObserveWidget, returnTypeObserveValue, new StringToClassUpdateValueStrategy(), new ClassToStringUpdateValueStrategy());
		
		IObservableValue nameObserveWidget = SWTObservables.observeText(txtMethodName, SWT.Modify);
		IObservableValue nameObserveValue = BeansObservables.observeValue(modelData, "name");
		nameBinding = m_bindingContext.bindValue(nameObserveWidget, nameObserveValue, null, null);
		
		return m_bindingContext;
	}

	public T getParameter() {
		if ( modelData != null && parameterIsValid() ){
			return modelData;
		}
		return null;
	}

	private boolean parameterIsValid() {
		return modelData != null && !modelData.getName().trim().isEmpty() && modelData.getType() != null;
	}

	public void clear() {
		setModelData(createNewParameter());
	}
	
	private T createNewParameter(){
		Class<T> parameterClass = getParameterClass();
		if ( parameterClass == null)
			return null;
		
		try {
			return parameterClass.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private Class<T> getParameterClass() {
		ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
		return (Class<T>) parameterizedType.getActualTypeArguments()[0];
	}
	
	public void setAddCallback(Action action) {
		this.addCallback = action;
	}

}
